Understanding Dependency Injection in ASP.NET Core

इस पोस्ट में ASP.NET Core में डिपेंडेंसी इंजेक्शन (Dependency Injection) को समझते हैं।

ASP.NET Core में, जब क्लास A को क्लास B के ऑब्जेक्ट की आवश्यकता होती है, तो हम कहते हैं कि क्लास A की क्लास B पर निर्भरता (Dependency) है।

यदि क्लास A सीधे new ऑपरेटर का उपयोग करके क्लास B का ऑब्जेक्ट बनाता है, तो यह टाइट कपलिंग (Tight Coupling) कहलाता है। टाइट कपलिंग एक अच्छी प्रैक्टिस नहीं मानी जाती है क्योंकि यह कोड को कम लचीला और टेस्ट करने में मुश्किल बना देती है।

इस समस्या से बचने के लिए, क्लास A अपने भीतर क्लास B के ऑब्जेक्ट को बनाने की जिम्मेदारी किसी और क्लास को दे देता है। जब क्लास A को क्लास B के ऑब्जेक्ट की आवश्यकता होती है, तो यह Dependency ऑब्जेक्ट बाहर से इंजेक्ट (Inject) किया जाता है। इसी प्रक्रिया को डिपेंडेंसी इंजेक्शन (Dependency Injection - DI) के रूप में जाना जाता है।

सरल शब्दों में, डिपेंडेंसी इंजेक्शन एक डिज़ाइन पैटर्न है जो आपको क्लासों के बीच की निर्भरताओं को ढीला करने (Decouple) में मदद करता है। 

डिपेंडेंसी इंजेक्शन के मुख्य प्रकार

डिपेंडेंसी इंजेक्शन मुख्य रूप से तीन तरीकों से प्रचलित है:

  1. कंस्ट्रक्टर इंजेक्शन (Constructor Injection): यह सबसे आम और पसंदीदा तरीका है। इसमें, निर्भरता (Dependency) को क्लास के कंस्ट्रक्टर के पैरामीटर के रूप में इंजेक्ट किया जाता है। जब क्लास का ऑब्जेक्ट बनाया जाता है, तो आवश्यक डिपेंडेंसी भी साथ में प्रदान की जाती है।
  2. मेथड इंजेक्शन (Method Injection): इस विधि में, डिपेंडेंसी ऑब्जेक्ट को किसी विशेष मेथड के पैरामीटर के रूप में इंजेक्ट किया जाता है। यह तब उपयोगी होता है जब डिपेंडेंसी केवल उस विशिष्ट मेथड के लिए आवश्यक हो।
  3. प्रॉपर्टी इंजेक्शन (Property Injection): इसमें डिपेंडेंसी को क्लास की पब्लिक प्रॉपर्टी के माध्यम से सेट किया जाता है। यह अक्सर वैकल्पिक निर्भरताओं के लिए उपयोग किया जाता है।

 कंस्ट्रक्टर इंजेक्शन का उदाहरण

मैं आपको ASP.NET Core में कंस्ट्रक्टर इंजेक्शन के माध्यम से डिपेंडेंसी इंजेक्शन (DI) को एक उदाहरण के साथ समझाता हूँ।

संकल्पना (Concept):

कंस्ट्रक्टर इंजेक्शन डिपेंडेंसी इंजेक्शन का सबसे आम और अनुशंसित तरीका है। इसमें, जिस क्लास को किसी अन्य क्लास (डिपेंडेंसी) की आवश्यकता होती है, वह उस डिपेंडेंसी को अपने कंस्ट्रक्टर के पैरामीटर के रूप में स्वीकार करता है। 

ASP.NET Core का इन-बिल्ट डिपेंडेंसी इंजेक्शन कंटेनर (जो कि एक IoC - Inversion of Control कंटेनर है) स्वचालित रूप से इन निर्भरताओं(Dependencies) को हल करता है और जब क्लास का एक इंस्टेंस बनाया जाता है, तो आवश्यक डिपेंडेंसी को कंस्ट्रक्टर के माध्यम से इंजेक्ट करता है।

उदाहरण (Example):

मान लीजिए हमारे पास एक ई-कॉमर्स एप्लीकेशन है जहाँ हमें ग्राहकों से संबंधित डेटा को संभालने की आवश्यकता है। हम एक ICustomerRepository इंटरफ़ेस और उसकी एक कंक्रीट इम्प्लीमेंटेशन CustomerRepository बनाते हैं। फिर, हम एक CustomerService क्लास बनाते हैं जिसे ICustomerRepository की आवश्यकता होगी।

चरण 1: इंटरफ़ेस परिभाषित करें (Define an Interface)

यह इंटरफ़ेस डेटा एक्सेस लॉजिक के लिए एक कॉन्ट्रैक्ट बनाता है।

// Interfaces/ICustomerRepository.cs
public interface ICustomerRepository
{
    string GetCustomerNameById(int id);
}

चरण 2: इंटरफ़ेस को लागू करें (Implement the Interface)

यह ICustomerRepository इंटरफ़ेस का कंक्रीट इम्प्लीमेंटेशन है। यह वास्तव में डेटाबेस से डेटा प्राप्त करने का अनुकरण कर सकता है।

// Services/CustomerRepository.cs
public class CustomerRepository : ICustomerRepository
{
    public string GetCustomerNameById(int id)
    {
        // यहाँ हम डेटाबेस से ग्राहक का नाम प्राप्त करने का अनुकरण कर रहे हैं
        // वास्तविक एप्लीकेशन में, यह एक डेटाबेस कॉल होगा
        if (id == 1)
        {
            return "Amit Kumar";
        }
        else if (id == 2)
        {
            return "Pooja Singh";
        }
        else
        {
            return "Unknown customer";
        }
    }
}

चरण 3: कंस्ट्रक्टर इंजेक्शन का उपयोग करने वाली क्लास (Class Using Constructor Injection)

यह हमारी CustomerService क्लास है जिसे ICustomerRepository की आवश्यकता है। ध्यान दें कि ICustomerRepository को कंस्ट्रक्टर के पैरामीटर के रूप में कैसे लिया गया है।

// Services/CustomerService.cs

public class CustomerService
{
    private readonly ICustomerRepository _customerRepository;

    // कंस्ट्रक्टर इंजेक्शन यहाँ होता है
    public CustomerService(ICustomerRepository customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public string GetCustomerDetails(int customerId)
    {
        string customerName = _customerRepository.GetCustomerNameById(customerId);
        return $"ग्राहक ID: {customerId}, नाम: {customerName}";
    }
}

चरण 4: डिपेंडेंसी को रजिस्टर करें (Register Dependencies in Program.cs)

ASP.NET Core में, आपको Program.cs (या पहले की परियोजनाओं में Startup.cs) फ़ाइल में अपनी डिपेंडेंसी को DI कंटेनर के साथ रजिस्टर करना होगा। यह कंटेनर को बताता है कि जब ICustomerRepository का इंस्टेंस मांगा जाए, तो उसे CustomerRepository का इंस्टेंस प्रदान करना चाहिए।

// Program.cs (ASP.NET Core 6.0+)
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using YourNamespace.Interfaces; // आपके इंटरफ़ेस के Namespace को बदलें
using YourNamespace.Services;   // आपकी सेवाओं के Namespace को बदलें

var builder = WebApplication.CreateBuilder(args);

// यहाँ हम अपनी डिपेंडेंसी को DI कंटेनर के साथ रजिस्टर करते हैं

// AddTransient: हर बार जब ICustomerRepository का अनुरोध किया जाता है, तो एक नया CustomerRepository इंस्टेंस बनाया जाता है।
// AddScoped: एक HTTP अनुरोध के दायरे में एक ही इंस्टेंस।
// AddSingleton: पूरे एप्लीकेशन के जीवनकाल में एक ही इंस्टेंस।

builder.Services.AddTransient<ICustomerRepository, CustomerRepository>();

builder.Services.AddTransient<CustomerService>(); // CustomerService को भी रजिस्टर करें

var app = builder.Build();

// .... अन्य मिडिलवेयर और कॉन्फ़िगरेशन ....
// एक API एंडपॉइंट या MVC कंट्रोलर में इसका उपयोग कैसे किया जाएगा

app.MapGet("/customer/{id}", ([FromServices] CustomerService customerService, int id) =>

{
    return customerService.GetCustomerDetails(id);
});

app.Run();

यह कैसे काम करता है (How it works):

  1. जब एक HTTP अनुरोध /customer/1 पर आता है, तो ASP.NET Core app.MapGet में परिभाषित डेलिगेट को एक्सेक्यूट करता है।
  2. इस डेलिगेट में, हम [FromServices] CustomerService customerService का उपयोग कर रहे हैं। यह ASP.NET Core DI कंटेनर को बताता है कि CustomerService का एक इंस्टेंस प्रदान करें।
  3. DI कंटेनर देखता है कि CustomerService के कंस्ट्रक्टर को ICustomerRepository की आवश्यकता है।
  4. कंटेनर ने पहले ही ICustomerRepository को CustomerRepository के रूप में पंजीकृत किया है (builder.Services.AddTransient<ICustomerRepository, CustomerRepository>();)
  5. तो, कंटेनर CustomerRepository का एक नया इंस्टेंस बनाता है।
  6. फिर, यह CustomerRepository इंस्टेंस को CustomerService के कंस्ट्रक्टर में पास करता है।
  7. इस प्रकार, CustomerService क्लास को ICustomerRepository का इंस्टेंस मिल जाता है, बिना इस बात की चिंता किए कि इसे कैसे बनाया गया था।

कंस्ट्रक्टर इंजेक्शन के लाभ (Benefits of Constructor Injection):

  1. ढीला कपलिंग (Loose Coupling): CustomerService को CustomerRepository के बारे में कुछ भी जानने की आवश्यकता नहीं है कि वह कैसे काम करता है या उसे कैसे बनाया जाता है। वह केवल इंटरफ़ेस ICustomerRepository पर निर्भर करता है।
  2. परीक्षण योग्यता (Testability): चूंकि निर्भरताएं कंस्ट्रक्टर के माध्यम से इंजेक्ट की जाती हैं, इसलिए आप आसानी से परीक्षण के लिए ICustomerRepository के मॉक (Mock) या स्टब (Stub) इम्प्लीमेंटेशन को पास कर सकते हैं, जिससे यूनिट टेस्टिंग बहुत आसान हो जाती है।
  3. कोड की पठनीयता (Code Readability): कंस्ट्रक्टर स्पष्ट रूप से उस क्लास की सभी आवश्यक निर्भरताओं को दर्शाता है।
  4. कम त्रुटियाँ (Reduced Errors): यदि कोई आवश्यक निर्भरता प्रदान नहीं की जाती है, तो DI कंटेनर स्टार्टअप पर एक त्रुटि फेंक देगा, जिससे रनटाइम समस्याओं से बचा जा सकेगा।

यह उदाहरण ASP.NET Core में कंस्ट्रक्टर इंजेक्शन के माध्यम से डिपेंडेंसी इंजेक्शन को समझने में आपकी मदद करेगा। यह मॉडर्न और मेंटेन करने योग्य एप्लीकेशन बनाने के लिए एक मूलभूत पैटर्न है।

टिप्पणियाँ

इस ब्लॉग से लोकप्रिय पोस्ट

Differences between in-process and out-of-process hosting models

Web Fundamental Concepts in Hindi for Beginners - FAQs with their Answers Part-1

Introduction to ASP.NET Core and Web Frameworks